package oauth2

import (
	"gitee.com/filters/reader/wviper"
	"gitee.com/filters/utils/conversion"
	"github.com/gin-gonic/gin"
	"github.com/go-oauth2/oauth2/v4"
	"github.com/go-oauth2/oauth2/v4/manage"
	"github.com/go-oauth2/oauth2/v4/models"
	"github.com/go-oauth2/oauth2/v4/server"
	"github.com/go-oauth2/oauth2/v4/store"
	"github.com/go-session/session"
	"github.com/spf13/cast"
	"net/http"
)

const SourceDataPathName = "Oauth2"

var (

	srv      *server.Server
	config   *OauthConfig
	storage  session.Store
)

type OauthSrv struct {
	SrvRelated
	manager  *manage.Manager
	Gen      oauth2.AccessGenerate               `json:"gen"`   //个性化token
	Types    []oauth2.GrantType                  `json:"types"` //容许登录类型
	Handler  server.UserAuthorizationHandler     //内部校验
	Phandler server.PasswordAuthorizationHandler //用户名密码校验
	source map[string]interface{}
	es       *gin.Engine
}

type OauthConfig struct {
	JwtSecret      string `json:"jwt_scret"`
	Domain      string `json:"domain"`
	Port        int64  `json:"port"`
	ServiceName string `json:"service_name"`
	RunMode     string `json:"run_mode"`
}

func GetServer() *server.Server {
	return srv
}
func GetConfig() *OauthConfig {
	return config
}

type OauthOpt func(o *OauthSrv)

func WithPwdHandler(handler server.PasswordAuthorizationHandler) OauthOpt {
	return func(o *OauthSrv) {
		o.Phandler = handler
	}
}

func WithHandler(handler server.UserAuthorizationHandler) OauthOpt {
	return func(o *OauthSrv) {
		o.Handler = handler
	}
}

func WithType(ty ...oauth2.GrantType) OauthOpt {
	return func(o *OauthSrv) {
		o.Types = ty
	}
}

func WithGen(gen oauth2.AccessGenerate) OauthOpt {
	return func(o *OauthSrv) {
		o.Gen = gen
	}
}


// LoadSrv 加载数据
func (o *OauthSrv) LoadSrv() *OauthSrv {
	conversion.ToStruct(o.source, config)
	// 设置 client 信息
	clientStore := store.NewClientStore()
	clientStore.Set(config.ServiceName, &models.Client{ID: config.ServiceName, Secret: config.JwtSecret, Domain: config.Domain})
	// 设置 manager, manager 参与校验 code/access token 请求
	o.manager = manage.NewDefaultManager()

	// 校验 redirect_uri 和 client 的 Domain, 简单起见, 不做校验
	o.manager.SetValidateURIHandler(func(baseURI, redirectURI string) error {
		return nil
	})
	o.manager.MustTokenStorage(store.NewMemoryTokenStore())
	// manger 包含 client 信息
	o.manager.MapClientStorage(clientStore)

	// server 也包含 manger, client 信息
	srv = server.NewServer(server.NewConfig(), o.manager)
	// 从请求中获取clientID 和 clientSecret, 在获取 access token 校验过程中会被用到
	srv.SetClientInfoHandler(func(r *http.Request) (clientID, clientSecret string, err error) {
		clientID = r.URL.Query().Get("client_id")
		clientSecret = r.URL.Query().Get("client_secret")
		return clientID, clientSecret, nil
	})
	// 用自定义的TokenGenerator替换默认的
	o.manager.MapAccessGenerate(o.Gen)

	// 设置为 authorization code 模式
	srv.SetAllowedGrantType(o.Types...)

	// authorization code 模式,  第一步获取code,然后再用code换取 access token, 而不是直接获取 access token
	srv.SetAllowedResponseType(oauth2.Code)

	// 校验授权请求用户的handler, 会重定向到 登陆页面, 返回"", nil
	srv.SetUserAuthorizationHandler(o.Handler)

	//校验授权请求的用户的账号密码, 给 LoginHandler 使用, 简单起见, 只允许一个用户授权
	srv.SetPasswordAuthorizationHandler(o.Phandler)
	// 允许使用 get 方法请求授权
	srv.SetAllowGetAccessRequest(true)
	return o
}

// Run 执行
func (o *OauthSrv) Run() error {
	gin.SetMode(config.RunMode)
	return o.es.Run(":" + cast.ToString(config.Port))
}

// HandleRouter 绑定路由
func (o *OauthSrv) HandleRouter(route func(r *gin.Engine)) *OauthSrv {
	route(o.es)
	return o
}
func New(opt ...OauthOpt) *OauthSrv {
	srvs := &OauthSrv{
		es: gin.New(),
	}
	config = &OauthConfig{}
	srv = &server.Server{}
	for _, oauthOpt := range opt {
		oauthOpt(srvs)
	}
	if srvs.source == nil {
		srvs.source = wviper.NewReader().Get(SourceDataPathName).(map[string]interface{})
	}
	return srvs
}
